#include"thread.h"
#include"reactor.h"

#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<fcntl.h>
Thread::Thread()
  {
     if(pthread_create(&tid_,NULL,taskFunc,this))
     {
         LOG_ERROR<<"create thread failed";
     }
     if(-1 == socketpair(AF_UNIX,SOCK_STREAM,0,channel_))
     {
        LOG_ERROR << strerror(errno);
     }
  }
Thread::~Thread(){}
void* Thread::taskFunc(void * arg)
{
    Thread * thread = static_cast<Thread * >(arg);
    thread->reactor_ = new Reactor();
    thread->reactor_->AddEventAndHander(thread->GetSocketPairSecond(),EV_READ | EV_PERSIST,Thread::SockPairEventCallback,arg);
    LOG_INFO<<thread->GetTid();
    thread->reactor_->Loop();
    return NULL;
}
void Thread::SockPairEventCallback(int fd,short events,void *arg)
{
   Thread * thread = static_cast<Thread * >(arg);
   int cfd =0;
   if(read(fd,&cfd,4) <= 0)
   {
     LOG_ERROR<<strerror(errno);
   }
   thread->reactor_->AddEventAndHander(cfd,EV_READ | EV_PERSIST, Thread::ClilentEventCallback,arg);
}
void Thread::ClilentEventCallback(int cfd,short events,void *arg)
{
        char * cliCmd[LAGE_BUF_LEN]={0};
        while(1)
       {
         char buff[SMALL_BUF_LEN] ={0};
         int n = recv(cfd,buff,1023,0);
         if(n <= 0)
         {
             LOG_INFO << "cli close";
             close(cfd);
             break;
         }
         char * cmd = GetCmd(buff,cliCmd);
         if(NULL == cmd)
         {
            send(cfd,ERR,strlen(ERR),0);
            
         }else if(strncmp(cmd,"ls",2)==0)
         {
             LSFile(cfd); 
         }
         else if(strncmp(cmd,"get",3) == 0)
         {
            if(NULL == cliCmd[1])
            {
              send(cfd,NO_FILENAME,strlen(NO_FILENAME),0);
            }
            SendFile(cfd,cliCmd[1]);
         }else if(strncmp(cmd,"up" ,2) == 0)
         {
          if(NULL == cliCmd[1])
            {
              send(cfd,NO_FILENAME,strlen(NO_FILENAME),0);
            }
            UpFile(cfd,cliCmd[1]);
         }else if(strncmp(cmd,"delete",6) == 0)
         {
          if(NULL == cliCmd[1])
            {
              send(cfd,NO_FILENAME,strlen(NO_FILENAME),0);
            }
            DeleteFile(cfd,cliCmd[1]);

         }
       }
}
int Thread::GetSocketPairFirst()const
{
   return channel_[0];
}
int Thread::GetSocketPairSecond()const
{
   return channel_[1];
}
pthread_t Thread::GetTid()const
{
  return tid_;
}

void Thread::LSFile(int cfd)
  {
     int pipefd[PIPE_BUF_LEN];
    if(-1 == pipe(pipefd))
    {
        send(cfd,PIPE_ERRO,strlen(PIPE_ERRO),0);
        return ;
    }
    pid_t pid  = fork();

    if(-1 == pid)
    {
        send(cfd,FORK_ERRO,strlen(FORK_ERRO),0);
        return ;

    }

    if(0 == pid)
    {
        close(pipefd[0]);//关闭读端
        dup2(pipefd[1],1);//用管道的写端覆盖标准输出
        dup2(pipefd[1],2);//用管道的写端覆盖标准错误
        if(-1 == chdir("../file"))
        {
          LOG_ERROR<<strerror(errno);
        }
        execlp("ls","ls",(char*)0);
        LOG_ERROR<<"cmd erro";
        exit(0);
    }
    if(pid > 0)
    {
      close(pipefd[1]);//关闭写端
      char read_pipe[ BIG_LAGE_BUF_LEN] ={"#ok"};
      read(pipefd[0],read_pipe +3, BIG_LAGE_BUF_LEN);
      send(cfd,read_pipe,strlen(read_pipe),0);

    }
    wait(NULL);//防止子进程变成僵死进程
  }
 void Thread::SendFile(int cfd ,char * filename)
{
   
   chdir("../file");
   int fd = open(filename,O_RDONLY);
   if(-1 == fd)
   {
    send(cfd,OPEN_ERR,strlen(OPEN_ERR),0);
    return ;
   }
   int filesize = lseek(fd,0,SEEK_END);
   if(-1 == filesize)
   {
    send(cfd,LSEEK_ERR,strlen(LSEEK_ERR),0);
   }
   lseek(fd,0,SEEK_SET);
   char statusBuff[SMALL_BUF_LEN] ={"#ok"};
   sprintf(statusBuff+3,"%d",filesize);
   send(cfd,statusBuff,strlen(statusBuff),0);
   memset(statusBuff,0,SMALL_BUF_LEN);
   if(recv(cfd,statusBuff,SMALL_BUF_LEN,0)<=0)
   {
      return ;
   }
   if(0 != strcmp(statusBuff,"#ok") )
   {
    return ;
   }
   char data[LAGE_BUF_LEN] ={0};
   int theNumberofRead =0;
   while((theNumberofRead = read(fd,data,LAGE_BUF_LEN))>0)
   {
     send(cfd,data,theNumberofRead,0);//可以用epoll设置一个写时间，当写缓冲区中有空闲了就来写
   }
   close(fd);
}

void  Thread::UpFile(int cfd,char * filename)
{
 chdir("../file");
 int fd = open(filename, O_WRONLY|O_CREAT,0600);
 if(-1 == fd)
 {
  send(cfd,NO_FILENAME,strlen(NO_FILENAME),0);
 }
  char status[SMALL_BUF_LEN]={0};
  int numberOfRecvBytes = recv(cfd,status,SMALL_BUF_LEN,0);
  if(numberOfRecvBytes <=0)
  {
    LOG_ERROR<<"cli erro close";
    return ;
  }else 
   {
       send(cfd,"#ok",strlen("#ok"),0);
       
   }
  int filesize = atoi(status+3);
  char dataBuff[LAGE_BUF_LEN]={0};
  int currFileSize =0;
  numberOfRecvBytes =0;
  while(1)
  {
     numberOfRecvBytes = recv(cfd,dataBuff,LAGE_BUF_LEN,0);
    if(numberOfRecvBytes <=0)
    {
        break;
    }
    write(fd,dataBuff,numberOfRecvBytes);
    currFileSize+= numberOfRecvBytes;
    if(currFileSize >= filesize)
    {
      break;
    }
    
  }
  if( currFileSize < filesize)
  {
       send(cfd,UP_ERR,strlen(UP_ERR),0);
  }else
  {
      send(cfd,"#ok",strlen("#ok"),0);
  }
  close(fd);
}
 void  Thread::DeleteFile(int cfd,char * filename)
{
  if(NULL == filename)
  {
    send(cfd,NO_FILENAME,strlen(NO_FILENAME),0);
    return ;
  }
  
    int pipefd[PIPE_BUF_LEN];
    if(-1 == pipe(pipefd))
    {
        send(cfd,PIPE_ERRO,strlen(PIPE_ERRO),0);
        return ;
    }
    pid_t pid  = fork();

    if(-1 == pid)
    {
        send(cfd,FORK_ERRO,strlen(FORK_ERRO),0);
        return ;

    }

    if(0 == pid)
    {
        close(pipefd[0]);//关闭读端
        dup2(pipefd[1],1);//用管道的写端覆盖标准输出
        dup2(pipefd[1],2);//用管道的写端覆盖标准错误
        if(-1 == chdir("../file"))
        {
          LOG_ERROR<<strerror(errno);
        }
        execlp("rm","rm",filename,(char*)0);
        LOG_ERROR<<"cmd erro";
        exit(0);
    }
    if(pid > 0)
    {
      close(pipefd[1]);//关闭写端
      char read_pipe[LAGE_BUF_LEN] ={"#erro"};
      if(read(pipefd[0],read_pipe +5,LAGE_BUF_LEN)>0)
      {

         send(cfd,read_pipe,strlen(read_pipe),0);
      }else
      {
        char sendSuccessMsg[LAGE_BUF_LEN] ={"#ok"};
        send(cfd,sendSuccessMsg,strlen(sendSuccessMsg),0);
      }
    
    }
    wait(NULL);//防止子进程变成僵死进程
}
char * Thread::GetCmd(char buff[],char * myargv[])
{
    if(buff == NULL || myargv == NULL)
    {
      return NULL;
    }
      int i = 0;
      char * ptr = NULL;
      char * s = strtok_r(buff," ",&ptr);
    while(NULL != s)
    {
       myargv[i++]=s;
       s= strtok_r(NULL," ",&ptr);
    }
    return myargv[0];
}